#include "cguiobject.h"

/**
 * ~CGuiObject - destructor
 */
CGuiObject::~CGuiObject() {
  free();
}
//---------------------------------------------------------------------------

/**
 * init - initialization of component
 */
void CGuiObject::init() {
  visible = true;
  disabled = false;
  ownerPtr = NULL;
  items = new vector<CLayoutItem*> ();
}
//---------------------------------------------------------------------------

/**
 * getX - returns x axis position of component
 * @return component x axis position
 */
int CGuiObject::getX() const {
  return x;
}
//---------------------------------------------------------------------------

/**
 * getY - returns y axis position of component
 * @return component y axis position
 */
int CGuiObject::getY() const {
  return y;
}
//---------------------------------------------------------------------------

/**
 * getWidth - returns width of component
 * @return component width
 */
unsigned short CGuiObject::getWidth() const {
  return width;
}
//---------------------------------------------------------------------------

/**
 * getHeight - returns height of component
 * @return component height
 */
unsigned short CGuiObject::getHeight() const {
  return height;
}
//---------------------------------------------------------------------------

/**
 * getStyle - returns graphical style of component
 * @return component style
 */
CGuiStyle CGuiObject::getStyle() const {
  return style;
}
//---------------------------------------------------------------------------

/**
 * getItemsPtr - returns pointer on list of pointers on component positions
 * @return pointer on list of pointers
 */
vector<CLayoutItem*>* CGuiObject::getItemsPtr() const {
  return items;
}
//---------------------------------------------------------------------------

/**
 * getItemPtr - returns pointer on position of given component
 * @return pointer on component
 */
CLayoutItem* CGuiObject::getItemPtr(TIndex index) const {
  return (*items)[index];
}
//---------------------------------------------------------------------------

/**
 * getOwnerPtr - returns pointer on components owner
 * @return pointer on component owner
 */
CGuiObject* CGuiObject::getOwnerPtr() const {
  return ownerPtr;
}
//---------------------------------------------------------------------------

/**
 * isVisible - returns true if component is visible
 * @return true/false if component is/is not visible
 */
bool CGuiObject::isVisible() const {
  return visible;
}
//---------------------------------------------------------------------------

/**
 * isDisabled - returns true if component is disabled
 * @return true/false if component is/is not disabled
 */
bool CGuiObject::isDisabled() const {
  return disabled;
}
//---------------------------------------------------------------------------

/**
 * setStyle - sets graphical style of component
 * @param style
 */
void CGuiObject::setStyle(CGuiStyle style) {
  this->style = style;
}
//---------------------------------------------------------------------------

/**
 * setVisible - sets visibility of component
 * @param visible
 */
void CGuiObject::setVisible(bool visible) {
  this->visible = visible;
}
//---------------------------------------------------------------------------

/**
 * setDisabled - sets if component is disabled
 * @param disabled
 */
void CGuiObject::setDisabled(bool disabled) {
  this->disabled = disabled;
}
//---------------------------------------------------------------------------

/**
 * setX - sets x axis position of component
 * @param x
 */
void CGuiObject::setX(int x) {
  this->x = x;
  vector<CLayoutItem*>::iterator i = items->begin();
  for (; i < items->end(); i++) {
    setItemXVars((*i)->getComponentPtr(), (*i)->getPosX(), (*i)->getSpanX());
  }
}
//---------------------------------------------------------------------------

/**
 * setY - sets y axis position of component
 * @param y
 */
void CGuiObject::setY(int y) {
  this->y = y;
  vector<CLayoutItem*>::iterator i = items->begin();
  for (; i < items->end(); i++) {
    setItemYVars((*i)->getComponentPtr(), (*i)->getPosY(), (*i)->getSpanY());
  }
}
//---------------------------------------------------------------------------

/**
 * setOwnerPtr - sets pointer on owner of component
 * @param ownerPtr
 */
void CGuiObject::setOwnerPtr(CGuiObject* ownerPtr) {
  this->ownerPtr = ownerPtr;
}
//---------------------------------------------------------------------------

/**
 * setItemXVars - sets x axis position and dimension of component
 * @param ptr
 * @param posX
 * @param spanX
 */
void CGuiObject::setItemXVars(CGuiObject* ptr, TIndex posX, TIndex spanX) {
  ptr->setX(x + layout.calculateComponentCoordX(posX));
  ptr->setWidth(layout.calculateComponentWidth(posX, spanX));
}
//---------------------------------------------------------------------------

/**
 * setItemYVars - sets y axis position and dimension of component
 * @param ptr
 * @param posY
 * @param spanY
 */
void CGuiObject::setItemYVars(CGuiObject* ptr, TIndex posY, TIndex spanY) {
  ptr->setY(y + layout.calculateComponentCoordY(posY));
  ptr->setHeight(layout.calculateComponentHeight(posY, spanY));
}
//---------------------------------------------------------------------------

/**
 * setWidth - sets width of component
 * @param width
 */
void CGuiObject::setWidth(unsigned short width) {
  this->width = width;
}
//---------------------------------------------------------------------------

/**
 * setHeight - sets height of component
 * @param height
 */
void CGuiObject::setHeight(unsigned short height) {
  this->height = height;
}
//---------------------------------------------------------------------------

/**
 * addItem - adds new component
 * @param itemPtr
 * @param posX
 * @param posY
 * @param spanX
 * @param spanY
 */
void CGuiObject::addItem(CGuiObject* itemPtr, TIndex posX, TIndex posY,
    TIndex spanX, TIndex spanY) {

  // Sets component parameters, based upon layout
  setItemXVars(itemPtr, posX, spanX);
  setItemYVars(itemPtr, posY, spanY);
  itemPtr->setOwnerPtr(this);
  items->push_back(new CLayoutItem(itemPtr, posX, posY, spanX, spanY));
  itemPtr->onAdd();
}
//---------------------------------------------------------------------------

/**
 * draw - draw component
 * @param rendererPtr
 */
void CGuiObject::draw(CGuiRenderer* rendererPtr) {

  // If component is not visible, return
  if (!visible) {
    return;
  }

  // Draw borders and base of component
  drawBorder(rendererPtr);
  drawBase(rendererPtr);

  // Draw body of the component
  drawSelf(rendererPtr);

  // Draw children components
  drawChildren(rendererPtr);
}
//---------------------------------------------------------------------------

/**
 * drawBase - draws base of component (background)
 * @param rendererPtr
 */
void CGuiObject::drawBase(CGuiRenderer* rendererPtr) {
  unsigned short l(x + style.getBorder().getSize());
  unsigned short t(y + style.getBorder().getSize());
  unsigned short r(x + width - style.getBorder().getSize());
  unsigned short b(y + height - style.getBorder().getSize());
  rendererPtr->drawRect(l, t, r, b, style.getAlpha(), style.getColor(),
      style.getImgId());
}
//---------------------------------------------------------------------------

/**
 * drawBorder - draws borders of component
 * @param rendererPtr
 */
void CGuiObject::drawBorder(CGuiRenderer* rendererPtr) {

  // Draw borders if their width is not zero
  if (style.getBorder().getSize()) {
    int l(x), t(y), r(x + width), b(y + height);
    unsigned short bs(style.getBorder().getSize());
    unsigned char ba(style.getBorder().getAlpha());
    CColor bc(style.getBorder().getColor());

    // If border overlaps dimensions of component, throw exception
    if ((bs << 1) > width || (bs << 1) > height) {
      throw CGuiBorderOverlapException(getClassName(), "drawBorder");
    }

    // Draw border
    rendererPtr->drawRect(l, t, r, t + bs, ba, bc, -1);
    rendererPtr->drawRect(l, b - bs, r, b, ba, bc, -1);
    rendererPtr->drawRect(l, t + bs, l + bs, b - bs, ba, bc, -1);
    rendererPtr->drawRect(r - bs, t + bs, r, b - bs, ba, bc, -1);
  }
}
//---------------------------------------------------------------------------

/**
 * drawChildren - draw nested components
 * @param rendererPtr
 */
void CGuiObject::drawChildren(CGuiRenderer* rendererPtr) {

  // Overlapping components
  vector<CGuiObject*> ptrs;

  // Draw components, except those overlapping
  vector<CLayoutItem*>::iterator i = items->begin();
  for (; i < items->end(); i++) {
    CRect<int> tmp;
    if ((*i)->getComponentPtr()->isOverlap(tmp)) {
      ptrs.push_back((*i)->getComponentPtr());
    } else {
      (*i)->getComponentPtr()->draw(rendererPtr);
    }
  }

  // Draw overlapping components
  for (vector<CGuiObject*>::iterator i = ptrs.begin(); i < ptrs.end(); i++) {
    (*i)->draw(rendererPtr);
  }
}
//---------------------------------------------------------------------------

/**
 * dispatchMouseEvent - fowards mouse event to nested component
 * @param eventPtr
 * @return ukazatel na komponentu, na ktere je zjistena udalost
 */
CGuiObject* CGuiObject::dispatchMouseEvent(CMouseEvent* eventPtr) {
  vector<CLayoutItem*>::iterator i = items->begin();
  for (; i < items->end(); i++) {
    if ((*i)->getComponentPtr()->isFocused(eventPtr)) {
      return (*i)->getComponentPtr()->dispatchMouseEvent(eventPtr);
    }
  }
  return this;
}
//---------------------------------------------------------------------------

/**
 * free - frees nested component
 */
void CGuiObject::free() {
  if (items && items->size() > 0) {
    vector<CLayoutItem*>::iterator i = items->begin();
    for (; i < items->end(); i++) {
      delete *i;
    }
    items->clear();
    delete items;
    items = NULL;
  }
}
//---------------------------------------------------------------------------
